/*
 * (C) Copyright IBM Corp. 1999-2000  All rights reserved.
 *
 * US Government Users Restricted Rights Use, duplication or
 * disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
 *
 * The program is provided "as is" without any warranty express or
 * implied, including the warranty of non-infringement and the implied
 * warranties of merchantibility and fitness for a particular purpose.
 * IBM will not be liable for any damages suffered by you as a result
 * of using the Program. In no event will IBM be liable for any
 * special, indirect or consequential damages or lost profits even if
 * IBM has been advised of the possibility of their occurrence. IBM
 * will not be liable for any third party claims against you.
 */

package com.jp.xml.asn1;

import com.bening.smsapp.bootstrap.BootConfigParameters;
import com.bening.smsapp.constant.SmsAppConstant;
import com.ibm.xml.asn1.ASN1Syntax2DTD;
import com.ibm.xml.asn1.LabelSAX;
import com.ibm.xml.asn1.ParseException;
import com.ibm.xml.asn1.SAX2ASN1;
import com.ibm.xml.asn1.SAXEventDumper;
import com.ibm.xml.asn1.UnlabelSAX;
import com.ibm.xml.parser.DTD;
import com.ibm.xml.parser.Parser;

import java.io.*;

import org.apache.xerces.parsers.SAXParser;
import org.xml.sax.ErrorHandler;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;

/**
 * This is a sample program to illustrate how to use this package.
 * This class enables the following:
 *
 * - Translation from DER encoded ASN.1 data to a plain XML document
 *   or to a labeled one
 *
 * - Translation from a labeled XML document to a plain one or to DER
 *   encoded ASN.1 data
 *
 * @author Takeshi IMAMURA
 */
public class TranslatorXML implements ErrorHandler {
  private String opt;  // Option
  private String src;  // Source file
  private String des;  // Destination file
  private String dtd;  // DTD file
  private String dtdName;  // DTD name

  /**
   * Constructs an object and initializes some variables according to
   * the specified arguments.
   *
   * @param <CODE>args</CODE> arguments to this program.
   */
  public TranslatorXML(String args[]) {
    if (args.length < 1) {
      printHelpAndExit(1);
    }
    String s = args[0];
    int i = 1;
    if (s.equals("-a")
	|| s.equals("-x")
	|| s.equals("-xa")
	|| s.equals("-d")) {
      if (args.length-i < 1) {
	printHelpAndExit(1);
      }
      opt = s;
      src = args[i++];
      des = null;
      if (args.length-i > 0) {
	des = args[i];
      }
    } else if (s.equals("-ax")) {
      if (args.length-i < 3) {
	printHelpAndExit(1);
      }
      opt = s;
      src = args[i++];
      dtd = args[i++];
      dtdName = args[i++];
      des = null;
      if (args.length-i > 0) {
	des = args[i];
      }
    } else if (s.equals("-help")) {
      printHelpAndExit(0);

    } else {
      printHelpAndExit(1);
    }
  }

  /**
   * Prints the help message and exits this program with a status.
   *
   * @param <CODE>stat</CODE> a status of this program.
   */
  private void printHelpAndExit(int stat) {
    System.err.println("Usage: java asn1.Translator <option> <file> ...");
    System.err.println("where <option> and <file>s are:");
    System.err.println("  -a    src.der [des.xml]               translate ASN.1 into XML");
    System.err.println("  -ax   src.der src.dtd root [des.xml]  translate ASN.1 into XML and label it");
    System.err.println("  -x    src.xml [des.xml]               unlabel XML");
    System.err.println("  -xa   src.xml [des.der]               unlabel XML and translate it into ASN.1");
    System.err.println("  -d    src.asn [des.dtd]               translate ASN.1 syntax into DTD");
    System.err.println("  -help                                 print this message");

    System.exit(stat);
  }

  /**
   * Starts the translation specified by an option.
   */
  public void start() {
    try {
      if (opt.equals("-a")) {
	startAS();

      } else if (opt.equals("-ax")) {
	startASS();

      } else if (opt.equals("-x")) {
	startSS();

      } else if (opt.equals("-xa")) {
	startSSA();

      } else if (opt.equals("-d")) {
	startAD();
      }
    } catch (Exception e) {
      if (e instanceof SAXException) {
	Exception e_ = ((SAXException)e).getException();
	if (e_ != null) {
	  e = e_;
	}
      }
      e.printStackTrace();
      System.exit(1);
    }
  }

  /**
   * Translates DER encoded ASN.1 data into a plain XML document.
   *
   * @exception java.io.IOException -
   * @exception org.xml.sax.SAXException -
   */
  private void startAS() throws IOException, SAXException {
    //CSVEventDumper dump = new CSVEventDumper();
	com.jp.xml.asn1.SAXEventDumper dump = new com.jp.xml.asn1.SAXEventDumper();
    Writer out = new StringWriter();
    if (des != null) {
      out = new FileWriter(des);
    }
    dump.setWriter(out);
    dump.setXMLDeclaration("1.0", null);

    //com.jp.xml.asn1.Asn12Csv a2s = new com.jp.xml.asn1.Asn12Csv(dump);
    com.jp.xml.asn1.ASN12SAX a2s = new com.jp.xml.asn1.ASN12SAX(dump);
    a2s.setPartialDecoding(false);
    InputStream in = new FileInputStream(src);
    a2s.setInputStream(in);
    a2s.setEncoding("base64");
    a2s.start();
    System.out.println("Writing "+des+".csv");
 
    //a2s.writeToCsv(des);
  }

  /**
   * Translates DER encoded ASN.1 data into an XML document and labels
   * the document.
   *
   * @exception java.io.IOException -
   * @exception org.xml.sax.SAXException -
   */
  private void startASS() throws IOException, SAXException {
    SAXEventDumper dump = new SAXEventDumper();
    Writer out = new PrintWriter(System.out);
    if (des != null) {
      out = new FileWriter(des);
    }
    dump.setWriter(out);
    dump.setXMLDeclaration("1.0", null);
    dump.setDoctypeDeclaration(dtdName, this.dtd);

    LabelSAX lsax = new LabelSAX(dump);
    
    DTD dtd = readDTD(this.dtd);
    
    lsax.setDTD(dtd, dtdName);
    lsax.setEncoding("base64");

    com.jp.xml.asn1.ASN12SAX a2s = new com.jp.xml.asn1.ASN12SAX(lsax);
    InputStream in = new FileInputStream(src);
    a2s.setInputStream(in);
    a2s.setPartialDecoding(true);
    a2s.start();
    
  }

  /**
   * Reads a DTD from a file.
   *
   * @param <CODE>name</CODE> the name of the file containing a DTD.
   *
   * @return a DTD.
   *
   * @exception java.io.IOException -
   */
  private DTD readDTD(String name) throws IOException {
    Parser psr = new Parser(name);
    psr.setErrorHandler(this);

    Reader in = new FileReader(name);
    DTD dtd = psr.readDTDStream(in);

    return dtd;
  }

  /**
   * Unlabels a labeled XML document
   *
   * @exception java.io.IOException -
   * @exception org.xml.sax.SAXException -
   */
  private void startSS() throws IOException, SAXException {
    SAXEventDumper dump = new SAXEventDumper();
    Writer out = new PrintWriter(System.out);
    if (des != null) {
      out = new FileWriter(des);
    }
    dump.setWriter(out);
    dump.setXMLDeclaration("1.0", null);

    UnlabelSAX usax = new UnlabelSAX(dump);
    usax.setEncoding("base64");

    SAXParser psr = new SAXParser();
    psr.setContentHandler(usax);
    psr.setErrorHandler(this);
    psr.setFeature("http://xml.org/sax/features/validation", true);
    psr.parse(src);
  }

  /**
   * Unlabels a labeled XML document and translates it into DER
   * encoded ASN.1 data.
   *
   * @exception java.io.IOException -
   * @exception org.xml.sax.SAXException -
   */
  private void startSSA() throws IOException, SAXException {
    SAX2ASN1 s2a = new SAX2ASN1();
    OutputStream out = System.out;
    if (des != null) {
      out = new FileOutputStream(des);
    }
    s2a.setOutputStream(out);

    UnlabelSAX usax = new UnlabelSAX(s2a);

    SAXParser psr = new SAXParser();
    psr.setContentHandler(usax);
    psr.setErrorHandler(this);
    psr.setFeature("http://xml.org/sax/features/validation", true);
    psr.parse(src);
  }

  /**
   * Translates an ASN.1 abstract syntax definition into a DTD.
   *
   * @exception java.io.IOException -
   */
  private void startAD() throws IOException, ParseException {
    ASN1Syntax2DTD a2d = new ASN1Syntax2DTD();
    Reader in = new FileReader(src);
    Writer out = new PrintWriter(System.out);
    if (des != null) {
      out = new FileWriter(des);
    }
    a2d.translate(in, out);
  }

  //
  // ErrorHandler methods
  //

  /**
   * Receive notification of a warning.  The warning information is
   * printed.
   *
   * @param <CODE>exc</CODE> the warning information encapsulated in a
   * SAX parse exception.
   */
  public void warning(SAXParseException exc) {
    System.err.println("[Warning] "+getLocation(exc)+": "+exc.getMessage());
  }

  /**
   * Receive notification of a recoverable error.  The error
   * information is printed.
   *
   * @param <CODE>exc</CODE> the error information encapsulated in a
   * SAX parse exception.
   */
  public void error(SAXParseException exc) {
    System.err.println("[Error] "+getLocation(exc)+": "+exc.getMessage());
  }

  /**
   * Receive notification of a non-recoverable error.  The error
   * information is printed and the exception is thrown again.
   *
   * @param <CODE>exc</CODE> the error information encapsulated in a
   * SAX parse exception.
   *
   * @exception org.xml.sax.SAXException -
   */
  public void fatalError(SAXParseException exc) throws SAXException {
    System.err.println("[Fatal Error] "+getLocation(exc)+": "+exc.getMessage());
    throw exc;
  }

  /**
   * Gets the location where the exception is thrown.
   *
   * @param <CODE>exc</CODE> the warning or error information
   * encapsulated in a SAX parse exception.
   */
  private String getLocation(SAXParseException exc) {
    StringBuffer buf = new StringBuffer();

    String id = exc.getSystemId();
    if (id != null) {
      int i = id.lastIndexOf('/');
      if (i != -1) {
        id = id.substring(i+1);
      }
      if (!id.equals("")) {
	buf.append(id+", ");
      }
    }
    buf.append(exc.getLineNumber()+", ");
    buf.append(exc.getColumnNumber());

    return buf.toString();
  }

  /**
   * Crates this object and starts a translation.
   */
  public static void main(String args[]) {
		String fileConfigPath = System.getProperty(SmsAppConstant.CORE_CONFIGPATH); 
    	BootConfigParameters bootParam = BootConfigParameters.getInstance(fileConfigPath);
    TranslatorXML trans = new TranslatorXML(args);
    trans.start();
  }
}
